import type { textEditorProps } from '../../../../components/combined/text_editor'
import type { PageType } from '../../../../lib/page_handler/type'
import type {
  BaseStyleConfig,
  IPersonalizationItemConfig,
  PlatformTypeValue,
} from '../../../../types/interfaces'
import { TextEditor } from '../../../../components/combined/text_editor'
import { UserPref } from '../../../../lib/abstract'
import { BaiduPageType } from '../../../../lib/page_handler/platform/baidu/types'
import { createStandardStyleTag } from '../../../../lib/style_injector'
import { ToolKit } from '../../../../lib/utils/toolkit'
import {
  CustomElementStyleId,
  logger,
  SUPPORTED_PLATFORMS,
  VALID_RESULT,
} from '../../../../types/constants'
import { RESOURCE_ORIGIN, StyleInjectPosition } from '../../../../types/interfaces'

export class CustomCss extends UserPref {
  readonly id = 'custom_css'
  readonly name = 'CustomCss'
  readonly styleConfigKey = 'customCss'
  readonly notSupportedPages: Partial<Record<PlatformTypeValue, PageType[]>> | undefined = {
    [SUPPORTED_PLATFORMS.BAI_DU]: [
      BaiduPageType.NotFound,
    ],
  }

  readonly cssProperty = ''
  readonly cssValueSuffix = ''
  readonly defaultMode: ResourceOrigin = RESOURCE_ORIGIN.LOACL
  readonly cssStyleId: string = CustomElementStyleId.CustomCss

  // 启用页面类型隔离
  usePageTypeIsolation = true

  // 由于该设置项为单个，所以不需要缓存多个值，直接使用 string 类型即可
  cachedUrlContent: string | undefined
  constructor(config: IPersonalizationItemConfig) {
    super(config)

    this.modeIsUsed = true
  }

  createComponent(config: BaseStyleConfig, storedValue: string, mode: string, debouncedSave: (() => void) & { flush: () => void }): TextEditor {
    const text = mode === RESOURCE_ORIGIN.LOCAL ? storedValue : ''
    const url = mode !== RESOURCE_ORIGIN.LOCAL ? storedValue : ''

    const id = this.generateId(config.styleVar)
    const props: textEditorProps = {
      id: this.id,
      label: '样式表',
      mode: mode as any,
      type: 'css',
      text,
      url,
      urlContentType: 'text',
      textPlaceholder: '/* 选择一：在此输入自定义CSS代码（记得本地备份！！！）*/',
      urlPlaceholder: '选择二：输入文件URL，后续更新时请手动点击『加载』获取最新内容',
      onTextChange: (text: string) => {
        this.cachedValues.set(id, text)
        this.cachedModes.set(id, RESOURCE_ORIGIN.LOCAL)
        this.lastModes.set(id, this.cachedModes.get(id) as string)
        debouncedSave()
      },
      onUrlChange: (url: string, content: string | undefined) => {
        this.cachedValues.set(id, url)
        this.cachedModes.set(id, RESOURCE_ORIGIN.URL)
        this.lastModes.set(id, this.cachedModes.get(id) as string)
        this.cachedUrlContent = content || ''
        debouncedSave()
      },
    }
    return new TextEditor({
      ...props,
    })
  }

  /**
   * 检查 CSS 内容长度
   * @param css CSS 内容
   * @param limit 最大长度（KB）
   * @returns 是否有效
   */
  checkCss(css: string, limit: number = 500): { status: ValidResultType, error: string } {
    if (!css) {
      return {
        status: VALID_RESULT.INVALID.value,
        error: 'CSS 内容为空',
      }
    }

    // 1. HTML 标签检测
    const htmlPatterns = [
      // HTML注释 <!-- -->
      /<!--[\s\S]*?-->/,

      // DOCTYPE声明
      /<!DOCTYPE[\s\S]*?>/i,

      // 特殊标签 <?xml, <?php等
      /<\?[\s\S]*?\?>/,

      // CDATA部分
      /<!\[CDATA\[[\s\S]*?\]\]>/,
    ]

    if (htmlPatterns.some(pattern => pattern.test(css))) {
      return {
        status: VALID_RESULT.INVALID.value,
        error: '检测到HTML标签，这不是有效的CSS',
      }
    }

    // 2. 检查长度
    const byteSize = new Blob([css]).size
    if (byteSize > limit * 1024) {
      return {
        status: VALID_RESULT.INVALID.value,
        error: `CSS 内容过大 (${(byteSize / 1024).toFixed(2)}KB)，超过 ${limit}KB 限制`,
      }
    }

    // 3. 检查潜在的危险内容
    const dangerousPatterns = [
      // JavaScript 相关
      /javascript:/i,
      /expression\(/i,
      /eval\(/i,
      /setTimeout\(/i,
      /setInterval\(/i,
      /Function\(/i,

      // 数据URI
      // /url\(['"]?data:/i,
      /url\(['"]?http:/i,
      /url\(['"]?https:/i,

      // DOM 操作
      /document\./i,
      /window\./i,
      /localStorage\./i,
      /sessionStorage\./i,
    ]

    for (const pattern of dangerousPatterns) {
      if (pattern.test(css)) {
        return {
          status: VALID_RESULT.INVALID.value,
          error: `检测到潜在危险内容: ${pattern.toString()}`,
        }
      }
    }

    // 4. 基本语法验证
    try {
      // 创建一个元素来验证
      const style = document.createElement('style')
      style.textContent = css

      // 使用临时文档进行验证
      const doc = document.implementation.createHTMLDocument('')
      doc.head.appendChild(style)
      doc.head.removeChild(style)

      return {
        status: VALID_RESULT.VALID.value,
        error: '',
      }
    }
    catch (e) {
      return {
        status: VALID_RESULT.INVALID.value,
        error: `CSS 语法错误: ${e instanceof Error ? e.message : String(e)}`,
      }
    }
  }

  handleCheck(value: string, mode: string): { status: ValidResultType, error: string } {
    if (!value || value.length === 0)
      return { status: VALID_RESULT.VALID.value, error: '' }

    let checkResult = { status: VALID_RESULT.INVALID.value, error: '' }
    if (mode === RESOURCE_ORIGIN.URL) {
      checkResult = ToolKit.browser.url.isValidUrl(value, mode as FileUploadMode)
    }
    if (mode === RESOURCE_ORIGIN.LOCAL || (mode === RESOURCE_ORIGIN.URL && checkResult.status)) {
      const content = mode === RESOURCE_ORIGIN.LOCAL ? value : this.cachedUrlContent
      if (content)
        checkResult = this.checkCss(content, 500)
    }
    return checkResult
  }

  handleStorageSave(id: string, notEmpty: boolean, changed: boolean): void {
    this.setStorageValues(id, notEmpty, changed, {
      urlContent: this.cachedUrlContent,
    })
  }

  applyStyles(): void {
    this.getInstanceIds().forEach((id) => {
      const value = this.cachedValues.get(id) as string
      const mode = this.cachedModes.get(id) as string

      createStandardStyleTag(`${this.cssStyleId}`, mode === RESOURCE_ORIGIN.URL ? this.cachedUrlContent || '' : value, {
        allowEmpty: true,
        position: StyleInjectPosition.Last,
      })
      this.restoreContentIfEmpty(id)
    })
  }

  /**
   * 恢复内容（如果为空）
   */
  restoreContentIfEmpty(id: string): void {
    const $target = $(`.${this.config.className} .setting-item.render-${this.id}`)
    const $textInput = $target.find(`#${this.id}-text`)
    const $urlInput = $target.find(`#${this.id}-url`)
    const textContent = $textInput.val() as string
    const urlContent = $urlInput.val() as string

    if (textContent && urlContent && textContent.length === 0 && urlContent.length === 0) {
      const { value, mode } = this.getStorageValues(id)
      if (mode === RESOURCE_ORIGIN.URL) {
        $urlInput.val(value)
        logger.warn(`[${this.name}] 恢复URL模式缓存值: ${value}`)
      }
      else {
        $textInput.val(value)
        logger.warn(`[${this.name}] 恢复文本模式缓存值: ${value}`)
      }
    }
  }

  afterInit(): void {
    this.cachedUrlContent = this.getStorageValues(this.id)?.urlContent as string || ''
  }

  afterReset(): void {
    this.cachedUrlContent = ''
  }
}
